package com.xf.stackview.view;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.view.animation.LinearOutSlowInInterpolator;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.WindowManager;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.LinearInterpolator;
import android.widget.FrameLayout;
import android.widget.Scroller;

public class StackView extends FrameLayout {
    private float lastDownY;
    private float mScrollStart;
    private float mScrollEnd;
    private Scroller mScroller;
    private final static String TAG = "StackView";
    private int mScreenHeight;
    private VelocityTracker velocityTracker = VelocityTracker.obtain();
    private ValueAnimator valueAnimator;
    private int yVelocity;

    public StackView(@NonNull Context context) {
        super(context);
        inite();
    }

    public StackView(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        inite();
    }

    public StackView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        inite();

    }

    private void inite() {
        mScreenHeight = getScreenSize(getContext()).heightPixels;
        mScroller = new Scroller(getContext());
    }

    /**
     * 计算控件的大小
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int measureWidth = measureWidth(widthMeasureSpec);
        int measureHeight = measureHeight(heightMeasureSpec);        // 计算自定义的ViewGroup中所有子控件的大小
        measureChildren(widthMeasureSpec, heightMeasureSpec);        // 设置自定义的控件MyViewGroup的大小
        setMeasuredDimension(measureWidth, measureHeight);
    }

    private int measureWidth(int pWidthMeasureSpec) {
        int result = 0;
        int widthMode = MeasureSpec.getMode(pWidthMeasureSpec);// 得到模式
        int widthSize = MeasureSpec.getSize(pWidthMeasureSpec);// 得到尺寸
        switch (widthMode) {        /**         * mode共有三种情况，取值分别为MeasureSpec.UNSPECIFIED, MeasureSpec.EXACTLY,
         * MeasureSpec.AT_MOST。		 * 		 * 		 * MeasureSpec.EXACTLY是精确尺寸，
         * * 当我们将控件的layout_width或layout_height指定为具体数值时如andorid
         * * :layout_width="50dip"，或者为FILL_PARENT是，都是控件大小已经确定的情况，都是精确尺寸。
         * * 		 * 		 * MeasureSpec.AT_MOST是最大尺寸，		 * 当控件的layout_width或layout_height指定为WRAP_CONTENT时
         * * ，控件大小一般随着控件的子空间或内容进行变化，此时控件尺寸只要不超过父控件允许的最大尺寸即可
         * * 。因此，此时的mode是AT_MOST，size给出了父控件允许的最大尺寸。		 * 		 *
         * * MeasureSpec.UNSPECIFIED是未指定尺寸，这种情况不多，一般都是父控件是AdapterView，		 * 通过measure方法传入的模式。		 */
            case MeasureSpec.AT_MOST:
            case MeasureSpec.EXACTLY:
                result = widthSize;
                break;
        }
        return result;
    }

    private int measureHeight(int pHeightMeasureSpec) {
        int result = 0;
        int heightMode = MeasureSpec.getMode(pHeightMeasureSpec);
        int heightSize = MeasureSpec.getSize(pHeightMeasureSpec);
        switch (heightMode) {
            case MeasureSpec.AT_MOST:
            case MeasureSpec.EXACTLY:
                result = heightSize;
                break;
        }
        return result;
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        // 记录总高度
        int mTotalHeight = 0;
        int paddingBottom = getPaddingBottom();
        int paddingLeft = getPaddingLeft();
        int paddingRight = getPaddingRight();
        int paddingTop = getPaddingTop();
        // 遍历所有子视图
        int childCount = getChildCount();
        for (int i = 0; i < childCount; i++) {
            View childView = getChildAt(i);            // 获取在onMeasure中计算的视图尺寸
            childView.setScaleX((float) (0.80f + i * 0.05));
            childView.setScaleY((float) (0.80f + i * 0.05));
            childView.setAlpha(.9f);
            int measureHeight = childView.getMeasuredHeight();
            int measuredWidth = childView.getMeasuredWidth();
            childView.layout(left, mTotalHeight + top, measuredWidth, mTotalHeight + measureHeight);
            mTotalHeight += measureHeight / 4;
        }

    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        velocityTracker.computeCurrentVelocity(500);
        velocityTracker.addMovement(event);
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
//                lastDownY = event.getY();
//                mScrollStart = getScrollY();
                break;
            case MotionEvent.ACTION_MOVE:
//                if (!mScroller.isFinished()) {
//                    mScroller.abortAnimation();
//                }
//                float currentY = event.getY();
//                float dy;
//                dy = lastDownY - currentY;
//                Log.d("test", "dy = " + dy);
//                Log.d("test", "getScrollY() = " + getScrollY());
//                Log.d("test", "getHeight()  = " + getHeight());
//                Log.d("test", "mScreenHeight()  = " + mScreenHeight);
//                Log.d("test", "getHeight() - mScreenHeight = " + (getHeight() - mScreenHeight));
//                if (getScrollY() < 0) {
//                    dy = 0;
//                    //最顶端，超过0时，不再下拉，要是不设置这个，getScrollY一直是负数
//                } else if (getScrollY() > getHeight()) {
//                    dy = 0;
//                    //滑到最底端时，不再滑动，要是不设置这个，getScrollY一直是大于getHeight() - mScreenHeight的数，无法再滑动
//                }
//                scrollBy(0, (int) dy);
//                //不断的设置Y，在滑动的时候子view就会比较顺畅
//                lastDownY = event.getY();
                break;
            case MotionEvent.ACTION_UP:
                yVelocity = (int) velocityTracker.getYVelocity();
                autoVelocityScroll(yVelocity);
                velocityTracker.clear();
                break;
        }
        return true;//需要返回true否则down后无法执行move和up操作
    }

    private void autoVelocityScroll(int yVelocity) {
        //惯性滑动的代码,速率和滑动距离,以及滑动时间需要控制的很好,应该网上已经有关于这方面的算法了吧。。这里是经过N次测试调节出来的惯性滑动
        if (Math.abs(yVelocity) < 50) {
            return;
        }
        if (valueAnimator != null && valueAnimator.isRunning()) {
            return;
        }
        for (int i = 1; i < getChildCount(); i++) {
            final View view = getChildAt(i);
            ValueAnimator valueAnimator = ValueAnimator.ofInt(0, yVelocity / 50).setDuration(Math.abs(yVelocity / (16 /i)));
            valueAnimator.setInterpolator(new DecelerateInterpolator());
            valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    int curValue = (int) animation.getAnimatedValue();

                    Log.d(TAG, "val=" + curValue + ">>>top=" + view.getTop());
                    if (view.getTop() + curValue > getChildAt(0).getTop())
                        view.layout(view.getLeft(), view.getTop() + curValue, view.getRight(), curValue + view.getBottom());
                }

            });
            valueAnimator.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {

                }
            });

            valueAnimator.start();
        }
    }

    /**
     * Scroller只是个计算器，提供插值计算，让滚动过程具有动画属性，但它并不是UI，也不是滑动辅助UI运动，反而是单纯地为滑动提供计算
     * 需要invalidate()之后才会调用,这个方法在onDraw()中调用
     */
    @Override
    public void computeScroll() {
        super.computeScroll();
        Log.d(TAG, "mScroller.getCurrY() " + mScroller.getCurrY());
        if (mScroller.computeScrollOffset()) {//是否已经滚动完成
            scrollTo(0, mScroller.getCurrY());//获取当前值，startScroll（）初始化后，调用就能获取区间值
            postInvalidate();
        }
    }

    /**
     * 获取屏幕大小，这个可以用一个常量不用每次都获取
     *
     * @param context
     * @return
     */
    public static DisplayMetrics getScreenSize(Context context) {
        DisplayMetrics metrics = new DisplayMetrics();
        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        wm.getDefaultDisplay().getMetrics(metrics);
        return metrics;
    }
}
